
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include "esp_log.h"

#include "xlx_common.h"
#include "xlx_func.h"
#include "xlx_platform.h"

static const char* TAG = "func";

static const uint16_t crctab16[] = {
 0X0000, 0X1189, 0X2312, 0X329B, 0X4624, 0X57AD, 0X6536, 0X74BF,
 0X8C48, 0X9DC1, 0XAF5A, 0XBED3, 0XCA6C, 0XDBE5, 0XE97E, 0XF8F7,
 0X1081, 0X0108, 0X3393, 0X221A, 0X56A5, 0X472C, 0X75B7, 0X643E,
 0X9CC9, 0X8D40, 0XBFDB, 0XAE52, 0XDAED, 0XCB64, 0XF9FF, 0XE876,
 0X2102, 0X308B, 0X0210, 0X1399, 0X6726, 0X76AF, 0X4434, 0X55BD,
 0XAD4A, 0XBCC3, 0X8E58, 0X9FD1, 0XEB6E, 0XFAE7, 0XC87C, 0XD9F5,
 0X3183, 0X200A, 0X1291, 0X0318, 0X77A7, 0X662E, 0X54B5, 0X453C,
 0XBDCB, 0XAC42, 0X9ED9, 0X8F50, 0XFBEF, 0XEA66, 0XD8FD, 0XC974,
 0X4204, 0X538D, 0X6116, 0X709F, 0X0420, 0X15A9, 0X2732, 0X36BB,
 0XCE4C, 0XDFC5, 0XED5E, 0XFCD7, 0X8868, 0X99E1, 0XAB7A, 0XBAF3,
 0X5285, 0X430C, 0X7197, 0X601E, 0X14A1, 0X0528, 0X37B3, 0X263A,
 0XDECD, 0XCF44, 0XFDDF, 0XEC56, 0X98E9, 0X8960, 0XBBFB, 0XAA72,
 0X6306, 0X728F, 0X4014, 0X519D, 0X2522, 0X34AB, 0X0630, 0X17B9,
 0XEF4E, 0XFEC7, 0XCC5C, 0XDDD5, 0XA96A, 0XB8E3, 0X8A78, 0X9BF1,
 0X7387, 0X620E, 0X5095, 0X411C, 0X35A3, 0X242A, 0X16B1, 0X0738,
 0XFFCF, 0XEE46, 0XDCDD, 0XCD54, 0XB9EB, 0XA862, 0X9AF9, 0X8B70,
 0X8408, 0X9581, 0XA71A, 0XB693, 0XC22C, 0XD3A5, 0XE13E, 0XF0B7,
 0X0840, 0X19C9, 0X2B52, 0X3ADB, 0X4E64, 0X5FED, 0X6D76, 0X7CFF,
 0X9489, 0X8500, 0XB79B, 0XA612, 0XD2AD, 0XC324, 0XF1BF, 0XE036,
 0X18C1, 0X0948, 0X3BD3, 0X2A5A, 0X5EE5, 0X4F6C, 0X7DF7, 0X6C7E,
 0XA50A, 0XB483, 0X8618, 0X9791, 0XE32E, 0XF2A7, 0XC03C, 0XD1B5,
 0X2942, 0X38CB, 0X0A50, 0X1BD9, 0X6F66, 0X7EEF, 0X4C74, 0X5DFD,
 0XB58B, 0XA402, 0X9699, 0X8710, 0XF3AF, 0XE226, 0XD0BD, 0XC134,
 0X39C3, 0X284A, 0X1AD1, 0X0B58, 0X7FE7, 0X6E6E, 0X5CF5, 0X4D7C,
 0XC60C, 0XD785, 0XE51E, 0XF497, 0X8028, 0X91A1, 0XA33A, 0XB2B3,
 0X4A44, 0X5BCD, 0X6956, 0X78DF, 0X0C60, 0X1DE9, 0X2F72, 0X3EFB,
 0XD68D, 0XC704, 0XF59F, 0XE416, 0X90A9, 0X8120, 0XB3BB, 0XA232,
 0X5AC5, 0X4B4C, 0X79D7, 0X685E, 0X1CE1, 0X0D68, 0X3FF3, 0X2E7A,
 0XE70E, 0XF687, 0XC41C, 0XD595, 0XA12A, 0XB0A3, 0X8238, 0X93B1,
 0X6B46, 0X7ACF, 0X4854, 0X59DD, 0X2D62, 0X3CEB, 0X0E70, 0X1FF9,
 0XF78F, 0XE606, 0XD49D, 0XC514, 0XB1AB, 0XA022, 0X92B9, 0X8330,
 0X7BC7, 0X6A4E, 0X58D5, 0X495C, 0X3DE3, 0X2C6A, 0X1EF1, 0X0F78,
};
// 计算给定长度数据的 16 位 CRC。
uint16_t xlx_crc16(const char *szdata,int len)
{
    uint16_t fcs = 0xffff; // 初始化
    while(len > 0){
        fcs = (fcs >> 8) ^ crctab16[(fcs ^ *szdata) & 0xff];
        len--;
        szdata++;
    }
    return ~fcs; // 取反
}

void xlx_print_hex(const char *tag,const char *data,int len){
    // if (!xlx_show_logger) return;
    if (len > 512) return;
    int i = 0;
    int x = 0;
    int max = 0;
    char *buf = NULL;
    char *p = NULL;
    int maxLen = 512;       //最大打印长度

    if(len <= 0){
        TUTU_LOGW(TAG, "%s() [%s] !!! len <= 0 !!!",__func__,tag);
        return;
    }

    x = len / 3;
    max = x > maxLen ? maxLen : len;        //最多只打印340个字节，超出的不打印
    buf = malloc(max*3 + 2);                //每个字节打3个字符，340x3=1020个字节
    if(buf == NULL){
        return;
    }
    
    p = buf;
    
    for(i=0;i<max;i++){
        sprintf(p,"%02X ", (uint8_t)data[i]);
        p += 3;
    }
    *p = '\0';

    ESP_LOGW(TAG, "[%s](len=%d): %s", tag, len, buf);
    free(buf);
}

typedef union{
    int a;
    char c;
}BigEndianTest;

int xlx_big_endian(){
    BigEndianTest test;
    test.a = 1;
    
    if(test.c == 1){
        //小端
        return 0;
    }else{
        //大端
        return 1;
    }
}

/**
 * 切割字符串
 * @param str 字符内容
 * @param split 切割符号
 * @param outarray 切割完返回的数组内容
 * @param outbuflen 用来装结果内容的大小
 * @param 返回 有多少个
* at+L342=action,Version
 */
int xlx_split_string(char *str,const char *split,char **outarray,int outbuflen){
    int count = 0;    
    char *token = NULL;

    /* 获取第一个子字符串 */
    token = strtok(str, split);

    /* 继续获取其他的子字符串 */
    while( token != NULL ) {
        if(outbuflen < count){
            break;
        }
        
        outarray[count] = token;
        count ++;
        token = strtok(NULL, split);
    }  
    // 最后有一个
    outarray[count++] = token;
    return count;
}

uint32_t xlx_htonl(uint32_t val){
    return ((val & 0xff000000) >> 24) |
               ((val & 0x00ff0000) >> 8) |
               ((val & 0x0000ff00) << 8) |
               ((val & 0x000000ff) << 24);
}


uint16_t xlx_htons(uint16_t val){
    return ((val & 0xff00) >> 8) | ((val & 0x00ff) << 8);
}

uint64_t xlx_htonll(uint64_t val)
{
    return (((uint64_t) xlx_htonl(val)) << 32) + xlx_htonl(val >> 32);
}

#if 1
const char Days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

static int mon_yday[2][12] =
{
    {0,31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
    {0,31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
};
 
int isleap(int year)
{
    return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0);
}

/*
*转换成时间戳
*/
uint32_t xlx_mktime(TutuTime *tt)
{
    uint32_t result = 0;
    int i = 0;
    result = (tt->year - 1970) * 365 * 24 * 3600 +
    (mon_yday[isleap(tt->year)][tt->mon-1] + tt->day - 1) * 24 * 3600 + tt->hour * 3600 + tt->min * 60 + tt->sec;
    for(i=1970; i < tt->year; i++){
        if(isleap(i)){
            result += 24 * 3600;
        }
    }
    return(result);
}

/*
*转换成时间戳
*/
uint32_t xlx_2timestamp_fast(TutuTime *tt){
    uint32_t result = 1123200;
    int i = 0;

    if(tt->year < 2021){
        return xlx_mktime(tt);
    }

    result += (tt->year - 1970) * 365 * 24 * 3600 +
    (mon_yday[isleap(tt->year)][tt->mon-1] + tt->day - 1) * 24 * 3600 + tt->hour * 3600 + tt->min * 60 + tt->sec;
    for(i=2021; i < tt->year; i++){
        if(isleap(i)){
            result += 24 * 3600;
        }
    }
    return(result);
}

/**
 * 时间戳转换成日期
 */
void xlx_localtime(uint32_t time,TutuTime *t)
{
    unsigned int Pass4year;
    int hours_per_year;

    //取秒时间
    t->sec=(int)(time % 60);
    time /= 60;
    //取分钟时间
    t->min=(int)(time % 60);
    time /= 60;
    //取过去多少个四年，每四年有 1461*24 小时
    Pass4year=((unsigned int)time / (1461L * 24L));
    //计算年份
    t->year=(Pass4year << 2) + 1970;
    //四年中剩下的小时数
    time %= 1461L * 24L;
    //校正闰年影响的年份，计算一年中剩下的小时数
    for (;;)
    {
        //一年的小时数
        hours_per_year = 365 * 24;
        //判断闰年
        if ((t->year & 3) == 0)
        {
            //是闰年，一年则多24小时，即一天
            hours_per_year += 24;
    }
        if (time < hours_per_year)
        {
            break;
        }
        t->year++;
        time -= hours_per_year;
    }
    //小时数
    t->hour=(int)(time % 24);
    //一年中剩下的天数
    time /= 24;
    //假定为闰年
    time++;
    //校正闰年的误差，计算月份，日期
    if((t->year & 3) == 0)
    {
        if (time > 60)
        {
            time--;
        }
        else
        {
            if (time == 60){
                t->mon = 1;
                t->day = 29;
                return ;
            }
        }
    }
    //计算月日
    for (t->mon = 0; Days[t->mon] < time;t->mon++)
    {
        time -= Days[t->mon];
    }

    t->day = (int)(time);
    t->mon += 1;        // Modify by Kenglee (月份是从0开始的)
    return;
}
#endif

//字符串拷贝
void xlx_strcopy(char *dst,int maxsize,const char *src){
    int i = 0;
    int n = strlen(src);
    char *tmp = dst;
    for(;i < maxsize && i < n;i++){
        *(tmp+i) = *(src+i);
    }
}

/**
 * 判断字符是否为ip，还是域名
 * @param host 字符串
 * @return 1:ip 0：域名
 */
char xlx_str_is_ip(const char *host){
    int n = 0;
    int i = 0;
    int count = 0;
    char c = 0;

    n = strlen(host);
    for(;i < n;i++){
        c = *(host + i);
        if((c >= '0' && c <= '9')){
            continue;
        }else if(c =='.'){
            count++;
        }else{
            return 0;
        }
    }

    if(count == 3){
        return 1;
    }

    return 0;
}

double xlx_gps_distance(double lng1,double lat1,double lng2,double lat2){
    double a,b,R;
    double d,sa2,sb2;

    R = 6378245;
    lat1 = lat1 * XLX_PI / 180.0;
    lat2 = lat2 * XLX_PI / 180.0;
    a = lat1 - lat2;
    b = (lng1 - lng2) * XLX_PI / 180.0;

    sa2 = sin(a/2.0);
    sb2 = sin(b/2.0);
    d = 2 * R * asin( sqrt(sa2 * sa2 + cos(lat1) * cos(lat2) * sb2 * sb2));
    return d;
}


void xlx_char2bcd(const char *data,int size,char *output){
    int i = 0;
    int j = 0;
    int bcd_size = 0;
    int a = 0;
    char c = 0;

    bcd_size = size/2;

    //char转bcd编码
    for(i = 0;i < bcd_size;i++){
        c = *(data + j);
        j++;

        if(c >='0' && c <= '9'){
            c = c - '0';
        }else if((c >= 'a' && c <= 'z') || ((c >= 'A' && c <= 'Z'))){
            c = c - 'a' + 0xa;
        }
        a = c << 4;


        c = *(data + j);
        j++;
        if(c>='0' && c <='9'){
            c = c - '0';
        }else if((c >= 'a' && c <= 'z') || ((c >= 'A' && c <= 'Z'))){
            c = c - 'a' + 0xa;
        }

        a = a + c;
        output[i] = (char)(a);
    }
}

/**
 * 经纬度转换成字符串
 * @param val 经度或纬度
 * @param pout 需传入的缓存区大小为12个字节以上,能得到转换成功后的结果
 * @param latlon 1:lat  0:lon
 * @return 
 */
void xlx_latlng2str(uint64_t val,char* pout,char latlon)
{
    uint32_t dtemp = 0;
    uint32_t xtemp = 0;
    val &= 0x7FFFFFFF;
    dtemp = val / 1000000;
    xtemp = val % 1000000;
    if(latlon == 1){
        sprintf(pout,"%0ld.%06ld",dtemp,xtemp);
    }else{
        sprintf(pout,"%0ld.%06ld",dtemp,xtemp);
    }
}

/**
 * 计算整数n二进制中有多少个1
 */
int xlx_count_bits(int64_t n) {
    int count = 0;
    while(n != 0) {
        n = n & (n-1);
        count++;
    }
    return count;
}

int str_replace(char* p_source, char* p_seach,char *p_repstr, char *p_result)
{
	int c = 0;
	int repstr_leng = 0;
	int searchstr_leng = 0;

	char *p1;
	char *presult = p_result;
	char *psource = p_source;
	char *prep = p_repstr;
	char *pseach = p_seach;
	int nLen = 0;

	repstr_leng = strlen(prep);
	searchstr_leng = strlen(pseach);

	do{ 
		p1 = strstr(psource,p_seach);
		if (p1 == 0)
		{
			strcpy(presult,psource);
			return c;
		}
		c++;  //匹配子串计数加1;

		// 拷贝上一个替换点和下一个替换点中间的字符串
		nLen = p1 - psource;
		memcpy(presult, psource, nLen);

		// 拷贝需要替换的字符串
		memcpy(presult + nLen,p_repstr,repstr_leng);

		psource = p1 + searchstr_leng;
		presult = presult + nLen + repstr_leng;
	}while(p1);

	return c;
}


/*
* 字符串转换为大写
*/
void str_to_upper(char *str) {
    for (int i = 0; i < strlen(str); i++) {
        str[i] = toupper(str[i]);
    }
}

/*
* 查找子串(pStrSub)位置
* 返回 找到的字符串首地址后面 +1
* 0表示未找到
* 例：
	search_sub_str_position("12345689", "23") 返回 3
*/ 
unsigned short search_sub_str_position(const char *pStrSub,const char *pStr)
{	
	unsigned short i, j, k;
	for(j=0;pStr[j];j++)
	{
		k=j;
		for(i=0;pStrSub[i];i++){
			if(pStrSub[i]!=pStr[k++])break;
		}
		if(i&&!pStrSub[i])return (j+i);
	}		
	return	0;
}
